using System;
using Cmc.Modbus.Base;
using NewLife;
using NewLife.IP;
using NewLife.Log;
using NewLife.Net;
using ILog = NewLife.Log.ILog;

namespace Cmc.Modbus
{
    public class TcpClient : IClient, IDisposable
    {

        private NetUri uri;
        private ISocketClient client;
        public ILog _log;
        private EventHandler<ReceivedEventArgs> _onReciveAsyncHandle;
        private readonly object lockRead = new object();

        public TcpClient(string ip, int port, EventHandler<ReceivedEventArgs> onReciveAsyncHandle = null, ILog log = null)
        {
            IP = ip;
            Port = port;
            _onReciveAsyncHandle = onReciveAsyncHandle;
            uri = new NetUri(NetType.Tcp, IP, Port);
            _log = log ?? XTrace.Log;
        }

        void CreateConnection()
        {
            client = uri.CreateRemote();
            client.Log = _log;
            client.LogSend = true;
            client.LogReceive = true;
            client.Opened += Client_Opened;
            client.Received += Client_Received; ;

            client.Closed += Client_Closed;
        }

        private ReceivedEventArgs lastData;
        private DateTime lastDateTime;

        private void Client_Received(object sender, ReceivedEventArgs e)
        {
            lastData = e;
            lastDateTime = DateTime.Now;
            try
            {
                byte[] bytes = e.Packet.ReadBytes(0, e.Packet.Count);

                _log.Info($"{client.Remote.Address}:{client.Remote.Port}接收数据{bytes.ToHex(" ")}");

                if (_onReciveAsyncHandle != null)
                {
                    e.Packet = bytes;
                    _onReciveAsyncHandle(sender, e);
                }
            }
            catch (Exception exception)
            {
                client.Log.Warn(exception.ToString());
            }
        }

        public override bool SendBytes(byte[] bytes)
        {
            if (TryConnect())
            {
                var result = client.Send(bytes);
                if (result == bytes.Length)
                {
                    return true;
                }
            }
            return false;
        }

        public override byte[] RecieveBytes()
        {
            var packet = client.Receive();
            return packet.ReadBytes(0, packet.Count);
        }

        bool TryConnect()
        {
            if (!IsConnected)
            {
                if (client != null)
                {
                    client.Dispose();
                }
                CreateConnection();
                try
                {
                    IsConnected = client.Open();
                }
                catch (Exception e)
                {
                    Console.WriteLine(e);
                }
                if (!IsConnected)
                {
                    _log.Warn($"位于网络地址的[{IP}:{Port}]TCP通讯连接失败！");
                    return false;
                }
            }
            return IsConnected;
        }

        public override byte[] RecieveBytes(byte[] sendBytes)
        {
            lock (lockRead)
            {
                if (TryConnect())
                {
                    var result = client.Send(sendBytes);
                    DateTime dtFlag = DateTime.Now;
                    if (result == sendBytes.Length)
                    {
                        //var packet = client.Receive();  //newlift框架问题，第一次数据不能同步读取
                        //return packet.ReadBytes(0, packet.Count);
                        while (dtFlag.AddMilliseconds(1000) > DateTime.Now) //1秒内等待异步读取
                        {
                            if (lastDateTime >= dtFlag)
                            {
                                var packet = lastData.Packet;
                                return packet.ReadBytes(0, packet.Count);
                            }
                        }
                    }
                }
            }
            return null;
        }

        private void Client_Closed(object sender, EventArgs e)
        {
            IsConnected = false;
            _log.Info($"位于网络地址的[{IP}:{Port}]TCP通讯已断开！");
        }
        private void Client_Opened(object sender, EventArgs e)
        {
            IsConnected = true;
            _log.Info($"位于网络地址的[{IP}:{Port}]TCP通讯已连接！");
        }
        public void Dispose()
        {
            client?.Dispose();
        }
    }
}
